#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
import random
import sys
import os
import time
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from models.database import get_db, TestCase
from src.api.api_manager import APIManager
from scripts.create_data_template import *
from src.db.db_operations import *
from config.config import settings

class MetaDataParser:
    """元数据解析器，用于解析和处理元数据"""
    
    def __init__(self, fields : list):
        self.fields = {}

        for field in fields:
            assert ("object_api_name" in field) and ("field_api_name" in field), "字段必须包含object_api_name和field_api_name"
            assert ("field_type" in field), "字段必须包含field_type"

            field_name = field["object_api_name"] + "." + field["field_api_name"]
            field_label_zh = field.get("field_label_zh", "无")
            field_label_en = field.get("field_label_en", "None")
            field_type = field["field_type"]

            is_required = field.get("is_required", 0)  
            is_unique = field.get("is_unique", 0)     
            is_muiltiple = field.get("is_multiple", 0)

            generation_rules = json.loads(field.get("generation_rules", "{}"))
            settings = generation_rules.get("settings", {})

            #create_at = field.get("create_at", str(int(time.time())))
            #update_at = field.get("update_at", str(int(time.time())))

            self.fields[field_name] = {
                "field_label_zh": field_label_zh,
                "field_label_en": field_label_en,
                "field_type"    : field_type,
                "is_required"   : is_required,
                "is_unique"     : is_unique,
                "is_multiple"   : is_muiltiple,
                "settings"      : settings
                #"create_at"     : create_at,
                #"update_at"     : update_at
            }

            # for key, value in settings.items():
            #     print(f"key : {key}")
            #     print(f"value : {value}")
            #     if key in ["required", "unique", "multiline"]:
            #         continue
            #     else:
            #         self.fields[field_name][key] = value
        # for key, value in self.fields.items():
        #     print(f"key : {key}")
        #     print(f"value : {value}")

    def _extract_constraints(self, field_def):
        """从字段设置中提取约束条件"""
        constraints = {}
        settings = field_def.get("settings", {})
        
        # 通用约束
        if "required" in settings:
            constraints["required"] = settings["required"]
        if "unique" in settings:
            constraints["unique"] = settings["unique"]
        if "multiple" in settings:
            constraints["multiple"] = settings["multiple"]
            
        # 类型特定约束
        if field_def["field_type"] == "text":
            constraints["maxLength"]     = settings.get("maxLength", 255)
            constraints["caseSensitive"] = settings.get("caseSensitive", False)

        elif field_def["field_type"] == "bigint" or field_def["field_type"] == "integer":
            constraints["maxLength"] = settings.get("maxLength", 18)

        elif field_def["field_type"] == "number":
            constraints["decimalPlacesNumber"] = settings.get("decimalPlacesNumber", None)
            constraints["displayAsPercentage"] = settings.get("displayAsPercentage", False)
            constraints["maxLengthOfInteger"]  = settings.get("maxLengthOfInteger", 18)
            constraints["maxLengthOfDecimal"]  = settings.get("maxLengthOfDecimal", 9)

        elif field_def["field_type"] == "date":
            None

        elif field_def["field_type"] == "datetime":
            None

        elif field_def["field_type"] == "mobile_number":
            None

        elif field_def["field_type"] == "email":
            None

        elif field_def["field_type"] == "option":
            constraints["globalOptionAPIName"] = settings.get("globalOptionAPIName", "")
            constraints["optionSource"]        = settings.get("optionSource", "custom")
            constraints["optionList"]          = settings.get("optionList", [])

            # {
            #     "active": true,
            #     "apiName": "option_52d86948bb9",
            #     "color": "blue",
            #     "description": null,
            #     "label": [
            #       {
            #         "language_code": 2052,
            #         "text": "选项1"
            #       }
            #     ]
            #   },

        elif field_def["field_type"] == "boolean":
            constraints["defaultValue"]         = settings.get("defaultValue", True)
            constraints["descriptionWhenFalse"] = settings.get("descriptionWhenFalse", {})
            constraints["descriptionWhenTrue"]  = settings.get("descriptionWhenTrue", {})

        elif field_def["field_type"] == "avater_or_logo":
            constraints["displayStyle"] = settings.get("displayStyle", "square")

        elif field_def["field_type"] == "multilingual":
            constraints["caseSensitive"] = settings.get("caseSensitive", False)
            constraints["maxLength"]     = settings.get("maxLength", 1000)

        elif field_def["field_type"] == "rich_text":
            constraints["maxLength"]     = settings.get("maxLength", 1000)

        elif field_def["field_type"] == "file":
            constraints["anyType"]        = settings.get("anyType", True)
            constraints["fileTypes"]      = settings.get("fileTypes", [])
            constraints["maxUploadedNum"] = settings.get("maxUploadedNum", 1)

        elif field_def["field_type"] == "auto_id":
            constraints["digitsNumber"] = settings.get("digitsNumber", 1)
            constraints["generateMethod"] = settings.get("generateMethod", "random")
            constraints["prefix"] = settings.get("prefix", "")
            constraints["startAt"] = settings.get("startAt", "1")
            constraints["suffix"] = settings.get("suffix", "")

        elif field_def["field_type"] == "formula":
            constraints["formula"]    = settings.get("formula", [])
            constraints["returnType"] = settings.get("returnType", "text")

        elif field_def["field_type"] == "rollup":
            constraints["fieldAPIName"]    = settings.get("fieldAPIName", None)
            constraints["functionType"] = settings.get("functionType", "count")
            constraints["lookupFieldAPIName"]    = settings.get("lookupFieldAPIName", "")
            constraints["objectAPIName"] = settings.get("objectAPIName", "")
            constraints["rangeFilter"]    = settings.get("rangeFilter", None)

            constraints["maxLengthOfInteger"]  = settings.get("maxLengthOfInteger", 18)
            constraints["maxLengthOfDecimal"]  = settings.get("maxLengthOfDecimal", 9)

        elif field_def["field_type"] == "lookup":
            constraints["displayStyle"]     = settings.get("displayStyle", "select")
            constraints["hierarchy"]        = settings.get("hierarchy", False)
            constraints["objectAPIName"]    = settings.get("objectAPIName", "")
            constraints["sortConditions"]   = settings.get("sortConditions", [])

        elif field_def["field_type"] == "reference_field":
            constraints["fieldAPIName"]      = settings.get("fieldAPIName", "")
            constraints["guideFieldAPIName"] = settings.get("returnType", "")

        elif field_def["field_type"] == "region":
            constraints["hasLevelStrict"] = settings.get("hasLevelStrict", True)
            constraints["strictLevel"]    = settings.get("strictLevel", 4)

        elif field_def["field_type"] == "decimal":
            constraints["decimalPlacesNumber"] = settings.get("decimalPlacesNumber", None)
            constraints["displayAsPercentage"] = settings.get("displayAsPercentage", False)
            constraints["maxLengthOfInteger"]  = settings.get("maxLengthOfInteger", 18)
            constraints["maxLengthOfDecimal"]  = settings.get("maxLengthOfDecimal", 9)

        return constraints

class DynamicObjectFactory:
    def __init__(self, object_id : str = ""):
        if not object_id:
            self.parser = None
        else:
            self.parse(object_id)

    # 解析对应对象的配置
    def parse(self, object_id : str):
        dbrunner = DbRunner(settings.DB_HOST, settings.DB_USER, settings.DB_PASSWORD, settings.DB_NAME)
        select_result = dbrunner.select_data('field_schema', columns='*', where=f"object_api_name = {object_id}") 
        self.parser = MetaDataParser(select_result)
        dbrunner.close()

    def create_object(self, fields : list = [], probabilities : dict = {}):
        obj = {}
        obj_field_g_type = {}

        for key in self.parser.fields.keys():
            dot_index = key.find('.')

            # 如果找到点号
            if dot_index != -1:
                field_name = key[dot_index + 1:]
                # field_names.append(key[dot_index + 1:])
            else:
                field_name = key
                # field_names.append(key)
            
            # 跳过系统字段，不添加到obj_field_g_type中
            if field_name in ["_createdAt", "_updatedAt", "_id", "_updatedBy", "_createdBy"]:
                continue
            
            if (fields != [] and field_name in fields) or fields == []:
                # print(key)
                # self.create_value(obj, key, {"none": 0.0, "normal": 0.6, "invalid": 0.4})
                generate_type = self.create_value(obj, key, probabilities=probabilities)
                obj_field_g_type[field_name] = generate_type
        
        # 判断引擎：根据字段的必填性和生成类型判断最终结果
        scenario = self._judge_scenario(obj_field_g_type)
        
        return obj, obj_field_g_type, scenario
    
    def _judge_scenario(self, obj_field_g_type: dict) -> str:
        """
        判断引擎：根据字段的必填性和生成类型判断最终结果
        
        Args:
            obj_field_g_type: 字段生成类型字典
            
        Returns:
            str: "normal" 或 "exception"
        """
        # 1. 检查必填字段是否为none
        for field_name, generate_type in obj_field_g_type.items():
            # 获取字段定义
            field_absolute_name = None
            for key in self.parser.fields.keys():
                if key.endswith(field_name):
                    field_absolute_name = key
                    break
            
            if field_absolute_name:
                field_def = self.parser.fields[field_absolute_name]
                is_required = field_def.get("is_required", 0)
                
                # 如果是必填字段但生成类型为none，直接返回exception
                if is_required and generate_type == "none":
                    return "exception"
        
        # 2. 检查是否有invalid字段
        for generate_type in obj_field_g_type.values():
            if generate_type == "invalid":
                return "exception"
        
        # 3. 如果前面都没命中，说明都是normal或none，返回normal
        return "normal"

    def get_generate_type(self, probabilities : dict = {}) -> str:
        """
        根据给定的概率分布随机选择生成类型，默认是1/3,1/3,1/3
        
        参数:
        probabilities (dict): 类型到概率的映射，例如{"none": 0.3, "normal": 0.3, "invalid": 0.4}

        none    说明这个字段直接不取
        normal  表示这个字段取正常值
        invalid 表示这个字段取异常值
        """
        if not probabilities:
            num = random.random()  # 生成[0,1)范围内的随机浮点数
    
            if num < 1/3:
                generate_type = "none"
            elif num < 2/3:
                generate_type = "normal"
            else:
                generate_type = "invalid"
        else:
            total_prob = sum(probabilities.values())
            if abs(total_prob - 1.0) > 1e-6:
                raise ValueError(f"概率总和应为1.0，实际为{total_prob:.6f}")

            rand_val = random.random()
    
            # 计算累积概率
            cumulative = 0.0
            for g_type, prob in probabilities.items():
                cumulative += prob
                if rand_val < cumulative:
                    generate_type = g_type
                    break
        return generate_type


    """
    生成对应字段的数据
    
    参数:
    obj                 (dict): 对象
    field_absolute_name (str): 字段的绝对名称，格式是{object_api_name}.{field_api_name},举个例子: object_cbb246f2bd1.datetime_09af1e5579a
    generate_type       (str):  "none","normal", "invalid"
    probabilities       (dict): 类型到概率的映射，例如{"none": 0.3, "normal": 0.3,  : 0.4}
    """
    def create_value(self, obj : dict, field_absolute_name : str, generate_type : str = "", probabilities : dict = {}) -> str:
        if not generate_type:
            generate_type = self.get_generate_type(probabilities)

        # 直接忽略该字段的生成
        if generate_type == "none":
            return "none"

        field_def = self.parser.fields[field_absolute_name]
        field_type = field_def["field_type"]
        constraints = self.parser._extract_constraints(field_def)

        # print(field_type)
        # print(generate_type)

        dot_index = field_absolute_name.find('.')

        # 获取字段的相对名词
        if dot_index != -1:
            field_relative_name = field_absolute_name[dot_index + 1:]
        else:
            field_relative_name = field_absolute_name

        # 特殊处理：_createdAt 和 _updatedAt 字段都返回 "none"
        if field_relative_name in ["_createdAt", "_updatedAt","_id","_updatedBy","_createdBy"]:
            return "none"

        if field_type == "text":
            maxLength     = constraints["maxLength"]
            caseSensitive = constraints["caseSensitive"]

            value = generate_text(maxLength)

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_text_invalid()
                #value += "烫" * (maxLength + 1 - len(value))

        elif field_type == "bigint" :
            maxLength = constraints["maxLength"]

            value = generate_bigint(maxLength)

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_bigint_invalid()
                

        elif field_type == "number":
            decimalPlacesNumber = constraints["decimalPlacesNumber"]
            displayAsPercentage = constraints["displayAsPercentage"]
            maxLengthOfInteger  = constraints["maxLengthOfInteger"]
            maxLengthOfDecimal  = constraints["maxLengthOfDecimal"]

            value = generate_number(maxLengthOfInteger, maxLengthOfDecimal)

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_number_invalid()

        elif field_def["field_type"] == "date":
            value = generate_date() 

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_date_invalid()
                
        elif field_def["field_type"] == "datetime":
            value = generate_datetime()

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_datetime_invalid()

        elif field_def["field_type"] == "mobile_number":
            value = generate_phone()

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_phone_invalid()

        elif field_def["field_type"] == "email":
            value = generate_email()

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_email_invalid()

        elif field_def["field_type"] == "option":
            value_choices = [d["apiName"] for d in constraints["optionList"]]
            value = random.choice(value_choices)

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_option_invalid()

        elif field_def["field_type"] == "boolean":
            value = random.choice([False, True, 1, 0, "1", "0"])

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_boolean_invalid()

        elif field_type == "avatar_or_logo":
            value = generate_random_avatar_data()

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = random.choice([-1, 12, "hello", "-1"])

        elif field_def["field_type"] == "multilingual":
            value = generate_multilingual()
            
            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_multilingual_invalid()

        elif field_def["field_type"] == "rich_text":
            return "none"

        elif field_def["field_type"] == "file":
            anyType = constraints["anyType"]
            fileTypes = constraints["fileTypes"]
            maxUploadedNum = constraints["maxUploadedNum"]

            value = generate_attachment(random.choice([i for i in range(1, maxUploadedNum + 1)]))

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_attachment(maxUploadedNum + 1)
        
        elif field_def["field_type"] == "auto_id":
            return "none"

        elif field_def["field_type"] == "formula":
            return "none"

        elif field_def["field_type"] == "rollup":
            return "none"

        elif field_def["field_type"] == "lookup":
            return "none"

        elif field_def["field_type"] == "reference_field":
            return "none"

        elif field_def["field_type"] == "region":
            hasLevelStrict = constraints["hasLevelStrict"]
            strictLevel    = constraints["strictLevel"]

            if hasLevelStrict:
                value = generate_region_data(strictLevel)
            else:
                value = generate_region_data(random.choice([i for i in range(1, 6)]))
            
            if generate_type == "invalid":
                if hasLevelStrict:
                    value = generate_region_data(random.choice([i for i in range(1, 6) if i != strictLevel]))
                else:
                    value = generate_region_data(0)

        elif field_def["field_type"] == "decimal":
            decimalPlacesNumber = constraints["decimalPlacesNumber"]
            displayAsPercentage = constraints["displayAsPercentage"]
            maxLengthOfInteger  = constraints["maxLengthOfInteger"]
            maxLengthOfDecimal  = constraints["maxLengthOfDecimal"]

            value = generate_number(maxLengthOfInteger, maxLengthOfDecimal)

            if generate_type == "invalid":
                # TODO: 可用ai来做
                value = generate_decimal_invalid()
        else :
            return "none"

        obj[field_relative_name] = value

        return generate_type


def generate_multiple_test_data(object_id: str, count: int = 10, probabilities: dict = None, output_file: str = "data/data_tmp.json"):
    """
    生成多条测试数据并保存到JSON文件
    
    Args:
        object_id (str): 对象ID
        count (int): 生成的数据条数
        probabilities (dict): 生成类型概率分布，例如{"none": 0.3, "normal": 0.5, "invalid": 0.2}
        output_file (str): 输出文件名
    """
    print(f"开始生成 {count} 条测试数据...")
    
    # 创建对象工厂
    object_factory = DynamicObjectFactory(object_id)
    
    if not object_factory.parser:
        print("❌ 无法获取字段信息，请检查数据库连接")
        return
    
    print(f"✅ 成功加载对象字段信息，共 {len(object_factory.parser.fields)} 个字段")
    
    # 生成多条数据
    all_results = []
    
    for i in range(count):
        print(f"正在生成第 {i+1}/{count} 条数据...")
        
        # 生成单条数据
        obj, obj_field_g_type, scenario = object_factory.create_object(probabilities=probabilities)
        
        # 构建结果对象
        result = {
            "index": i + 1,
            "data": obj,
            "field_generation_types": obj_field_g_type,
            "scenario": scenario,
            "timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
        }
        
        all_results.append(result)
        
        # 打印进度
        print(f"  第 {i+1} 条数据生成完成 - 场景: {scenario}")
    
    # 构建最终结果
    final_result = {
        "object_id": object_id,
        "total_count": count,
        "generation_config": {
            "probabilities": probabilities or {"none": 0.33, "normal": 0.34, "invalid": 0.33}
        },
        "generated_at": time.strftime("%Y-%m-%d %H:%M:%S"),
        "results": all_results
    }
    
    # 保存到JSON文件
    with open(output_file, 'w', encoding='utf-8') as f:
        json.dump(final_result, f, 
                 ensure_ascii=False,  # 确保非ASCII字符正常显示
                 indent=2,            # 缩进格式化
                 sort_keys=True)
    
    print(f"\n✅ 成功生成 {count} 条测试数据并保存到 {output_file}")
    
    # 统计场景分布
    scenario_stats = {}
    for result in all_results:
        scenario = result["scenario"]
        scenario_stats[scenario] = scenario_stats.get(scenario, 0) + 1
    
    print(f"\n📊 场景分布统计:")
    for scenario, count in scenario_stats.items():
        percentage = (count / len(all_results)) * 100
        print(f"  {scenario}: {count} 条 ({percentage:.1f}%)")


if __name__ == "__main__":
    # 配置参数
    object_id = '"object_cbb246f2bd1"'
    count = 10  # 生成10条数据
    probabilities = {
        "none": 0.2,    # 30% 概率生成none
        "normal": 0.6,  # 50% 概率生成normal
        "invalid": 0.2  # 20% 概率生成invalid
    }
    
    # 生成测试数据
    generate_multiple_test_data(
        object_id=object_id,
        count=count,
        probabilities=probabilities,
        output_file="data/data_tmp.json"
    )
